/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package io;

import io.midi.MidiSystemController;
import io.midi.MidiInListener;
import io.midi.GenericMidiController;
import io.midi.CoreMidiController;
import javax.sound.midi.*;
import tal.drivechain.chain.AbortChainException;
import tal.drivechain.plugin.Channel;
import tal.drivechain.plugin.Module;
import tal.drivechain.system.Globals;
import tal.drivechain.system.Globals.OS;
import tal.drivechain.variable.Variable;

import tal.drivechain.variable.types.DataType;
import tal.drivechain.variable.SetProperty.Flag;

/**
 *
 * @author Tal Eisenberg
 */
public class MidiIn extends Module implements MidiInListener {
    private Variable midiVar;
    private MidiSystemController controller;
    private boolean virtual;
    
    @Override
    public void setupProperties() throws IllegalArgumentException, AbortChainException {
        if (Globals.getOS()==OS.Mac)
            controller = new CoreMidiController();
        else
            controller = new GenericMidiController();
        controller.setMidiInListener(this);
        setPortId(props.getProperty("portId"), null);
        setPortName(props.getProperty("portName"), null);
        setVirtualPort(props.getProperty("virtualPort"), null);
        midiVar = new Variable("midiIn", DataType.MIDI, null, true);
    }
    
    public void setPortId(Object value, Flag flag) {
        if (value!=null) {
            int midiPort = (Integer)value;
            controller.setPort(midiPort, true);
            if (virtual) {
                virtual = false;
                ((CoreMidiController)controller).createVirtualPorts(null);
            }
        }
    } public Object getPortId() { if (!virtual) return controller.getPortId(); else return null; }

    public void setPortName(Object value, Flag flag) {
        if (value!=null) {
            int midiPort = controller.findPortByName((String)value);
            controller.setPort(midiPort, true);
            if (virtual) {
                virtual = false;
                ((CoreMidiController)controller).createVirtualPorts(null);
            }
        }
    } public Object getPortName() { if (!virtual) return controller.getPortName(); else return null; }

    public void setVirtualPort(Object value, Flag flag) {
        if (value!=null) {
            if (Globals.getOS()==OS.Mac) {
                log("Creating virtual port " + (String)value, MSG.ANOUNCE);
                ((CoreMidiController)controller).createVirtualPorts((String)value);
                virtual = false;
                setPortName(value, null);
                virtual = true;
            } else {
                virtual = false;
                throw new IllegalArgumentException("Virtual ports are only supported on Mac OSX.");
            }

        } else virtual = false;
    } public Object getVirtualPort() { if (!virtual) return null; else return controller.getPortName(); }
    
    @Override
    public void start() {
        super.start();
        controller.open();
        midiVar.setName(controller.getPortName().toLowerCase().replaceAll(" ", "_"));
        log("Midi port " + controller.getPortName() + " was successfully opened for input.", MSG.ANOUNCE);
    }
    
    @Override
    public void stop() {
        controller.close();
        super.stop();
    }
    

    public void receivedMidi(MidiMessage msg, long timestamp) {
        if (!isRunning()) return;
        midiVar.setValue(msg, true);
        sendToOutputs(midiVar, timestamp);
    }

    @Override
    protected void msgReceived(Variable in, long timestamp, Channel channel) {
    }
}